package hos.map.geometry;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import hos.map.area.AreaCalculatorInterface;
import hos.map.coordinate.CoordinateType;
import hos.map.coordinate.LatLng;
import hos.map.coordinate.LatLngBounds;
import hos.map.coordinate.LatLngCollection;
import hos.map.distance.CollectionDistanceCalculatorInterface;
import hos.map.distance.LengthUnit;

/**
 * <p>Title: MultiLatLng </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @version : 1.0
 * @date : 2023-12-07 22:08
 */
public abstract class GeometryCollection extends Geometry implements AreaCalculatorInterface,
        CollectionDistanceCalculatorInterface {

    protected LatLngCollection mList;

    protected GeometryCollection(CoordinateType type) {
        this(new LatLngCollection(type), type);
    }

    protected GeometryCollection(LatLngCollection list, CoordinateType type) {
        super(type);
        mList = list;
    }

    protected GeometryCollection(LatLng... points) {
        this(Arrays.asList(points), (CoordinateType) null);
    }

    protected GeometryCollection(Collection<LatLng> points) {
        this(points, (CoordinateType) null);
    }

    protected GeometryCollection(Collection<LatLng> points, CoordinateType type) {
        this(parseType(points, type));
        mList = new LatLngCollection(getType());
        mList.addAll(points);
    }


    private static CoordinateType parseType(Collection<LatLng> collection, CoordinateType type) {
        if (type != null) {
            return type;
        }
        if (collection == null || collection.isEmpty()) {
            return CoordinateType.wgs84;
        }
        for (LatLng point : collection) {
            if (point != null) {
                return point.getType();
            }
        }
        return CoordinateType.wgs84;
    }

    public boolean add(double latitude, double longitude) {
        if (mList == null) {
            mList = new LatLngCollection(getType());
        }
        return mList.add(latitude, longitude);
    }

    public boolean add(LatLng... latLng) {
        if (mList == null) {
            mList = new LatLngCollection(getType());
        }
        return Collections.addAll(mList, latLng);
    }

    public boolean addAll(List<LatLng> latLngList) {
        if (mList == null) {
            mList = new LatLngCollection(getType());
        }
        return mList.addAll(latLngList);
    }

    /**
     * 获取点位集合
     */
    public LatLngCollection getPoints() {
        return mList;
    }

    public boolean isEmpty() {
        return getCount() == 0;
    }

    /**
     * 获取点位数量
     */
    public int getCount() {
        if (mList == null || mList.isEmpty()) {
            return 0;
        }
        return mList.size();
    }

    /**
     * 获取第一个点位
     */
    public LatLng first() {
        if (mList == null || mList.isEmpty()) {
            return null;
        }
        return mList.first();
    }

    /**
     * 移除第一个点位并返回
     */
    public LatLng removeFirst() {
        if (isEmpty()) {
            return null;
        }
        return mList.removeAt(0);
    }

    /**
     * 获取最后一个点位
     */
    public LatLng last() {
        if (isEmpty()) {
            return null;
        }
        return mList.last();
    }

    /**
     * 移除最后一个点位并返回
     */
    public LatLng removeLast() {
        if (isEmpty()) {
            return null;
        }
        return mList.removeLast();
    }

    /**
     * 移除最后一个点位并返回
     */
    public LatLng removeAt(int index) {
        if (mList == null || mList.isEmpty()) {
            return null;
        }
        return mList.removeAt(index);
    }

    public void clear() {
        if (mList == null || mList.isEmpty()) {
            return;
        }
        mList.clear();
    }

    /**
     * 获取点集合形成线段的距离
     */
    @Override
    public double distance() {
        if (mList == null || mList.isEmpty()) {
            return 0;
        }
        return mList.distance();
    }

    /**
     * 获取点集合形成多变形的面积
     */
    @Override
    public double area() {
        if (mList == null || mList.isEmpty()) {
            return 0;
        }
        return mList.area();
    }


    public Polyline toPolyline() {
        if (mList == null) {
            mList = new LatLngCollection(getType());
        }
        return mList.toPolyline();
    }

    public Polygon toPolygon() {
        if (mList == null) {
            mList = new LatLngCollection(getType());
        }
        return mList.toPolygon();
    }

    /**
     * 转换成边界
     */
    public LatLngBounds toLatLngBounds() {
        if (mList == null) {
            return new LatLngBounds(getType());
        }
        return new LatLngBounds(mList);
    }

    public boolean isPolygonContains(LatLng point) {
        if (mList == null || mList.isEmpty()) {
            return false;
        }
        return mList.isPolygonContains(point);
    }

    /**
     * 获取点集合形成线段的距离
     */
    @Override
    public double distance(LengthUnit unit) {
        if (mList == null || mList.isEmpty()) {
            return 0;
        }
        return mList.distance(unit);
    }

    /**
     * 获取中心点位
     */
    public LatLng getCenter() {
        if (mList == null) {
            return null;
        }
        return mList.getCenter();
    }

    @Override
    public Map<String, Object> toMap() {
        Map<String, Object> data = super.toMap();
        if (mList != null) {
            List<Map<String, Object>> list = new ArrayList<>();
            for (LatLng point : mList) {
                list.add(point.toMap());
            }
            data.put("list", list);
        }
        return data;
    }

    @Override
    public String toJson() {
        Map<String, Object> data = toMap();
        Set<String> keySet = data.keySet();
        StringBuilder builder = new StringBuilder();
        builder.append("{");
        for (String key : keySet) {
            if (builder.length() > 1) {
                builder.append(",");
            }
            builder.append("\"").append(key)
                    .append("\"").append(":");
            if (key.equals("list")) {
                builder.append(mList.toJson());
            } else {
                Object value = data.get(key);
                if (value instanceof String) {
                    builder.append("\"")
                            .append(value)
                            .append("\"");
                } else {
                    builder.append(value);
                }
            }
        }
        builder.append("}");
        return builder.toString();
    }
}
